package com.shawn.kaoshixingautobot;

import com.microsoft.playwright.*;
import com.microsoft.playwright.options.LoadState;
import com.microsoft.playwright.options.WaitForSelectorState;

import java.nio.file.Paths;
import java.util.Arrays;

import static com.microsoft.playwright.options.WaitForSelectorState.VISIBLE;

public class AutoExamStar {
    private Playwright playwright;
    public Page page;

    private final String LOGIN_URL = "https://www.kaoshixing.com/login/account/login/536246";
    private final String HOME_URL = "https://v.kaoshixing.com/exam/pc/home/#/";
    //    private final String EXAM_URL = "https://exam.kaoshixing.com/exam/exam_start/1696307";
    private String examNo = "1696307";
    private String examUrl = "https://exam.kaoshixing.com/exam/exam_start/" + examNo;
    //    private final String BEFORE_EXAM_URL = "https://exam.kaoshixing.com/exam/before_answer_notice/1696307";
    private String beforeExamUrl = "https://exam.kaoshixing.com/exam/before_answer_notice/" + examNo;
    private String username;
    private String password;

    // 循环次数
    private Integer times = 5;

    public AutoExamStar() {
        init();
    }

    public AutoExamStar(String examNo, String username, String password, Integer times) {
        this.examNo = examNo;
        this.username = username;
        this.password = password;
        this.times = times;

        this.examUrl = "https://exam.kaoshixing.com/exam/exam_start/" + this.examNo;
        this.beforeExamUrl = "https://exam.kaoshixing.com/exam/before_answer_notice/" + this.examNo;
        init();
    }

    private void init(){
        playwright = Playwright.create();
        Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions()
                .setHeadless(false)
                .setArgs(Arrays.asList("--start-maximized", "--disable-features=UseOzonePlatform")));
        BrowserContext context = browser.newContext(new Browser.NewContextOptions()
                .setViewportSize(null));
        page = context.newPage();
    }

    public void login() {
        page.navigate(LOGIN_URL);
        page.locator("#username").fill(username);
        page.locator("#userTypePwd").fill(password);
        Locator loginBtn = page.locator("#loginBtn");
        loginBtn.waitFor();
        loginBtn.click();
        page.waitForURL(HOME_URL);
        System.out.println("登录成功");
    }

    private String saveScreenshot(String prefix) {
        String path = "screenshots/" + prefix + "_" + System.currentTimeMillis() + ".png";
        page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get(path)));
        return path;
    }

    /**
     * 修复核心：1. 替换不支持的>>>选择器为标准CSS的>；2. 优化弹窗关闭逻辑
     */
    public void takeExam() {
        try {
            // 1. 关闭干扰弹窗
            closeInterferingModals();

            // 2. 定位答题卡容器（简化判断）
            System.out.println("定位答题卡容器...");
            Locator answerCardModal = page.locator(".modal-content:has-text('答题卡')"); // 直接用 CSS 伪类简化
            answerCardModal.waitFor(new Locator.WaitForOptions()
                    .setState(VISIBLE)
                    .setTimeout(15000));


            // 3. 定位最后一个 card-content（拆分步骤）
            Locator.WaitForOptions waitOptions = new Locator.WaitForOptions()
                    .setState(WaitForSelectorState.VISIBLE) // 目标状态：可见
                    .setTimeout(10000); // 超时时间10000毫秒（10秒）
            Locator cardContentList = answerCardModal.locator(".modal-body > .card-content-list");
            cardContentList.waitFor(waitOptions.setState(VISIBLE));
            Locator lastCardContent = cardContentList.locator(".card-content:last-child");
            lastCardContent.waitFor(waitOptions.setState(VISIBLE));

            // 4. 定位最后一道题链接（拆分步骤，避免链式过长）
            Locator boxList = lastCardContent.locator(".box-list");
            boxList.waitFor(waitOptions.setState(VISIBLE));
            // 4. 定位最后一道题的a标签 → 再定位其内部的div子元素
            Locator lastQuestionLink = boxList.locator("a:last-child");
            lastQuestionLink.waitFor(new Locator.WaitForOptions() // 先确保a标签存在
                    .setState(WaitForSelectorState.HIDDEN) // 只需要存在于DOM中，不强制可见
                    .setTimeout(10000));

            // 定位a标签内的div子元素（实际点击目标）
            Locator lastQuestionDiv = lastQuestionLink.locator("> div"); // > 表示直接子元素
            lastQuestionDiv.waitFor(new Locator.WaitForOptions()
                    .setState(WaitForSelectorState.VISIBLE)
                    .setTimeout(15000));
            System.out.println("已定位到最后一道题的div子元素");

            // 滚动到该元素（确保在视口内）
            lastQuestionDiv.scrollIntoViewIfNeeded();
            page.waitForTimeout(500);

            // 点击div子元素
            lastQuestionDiv.click();
            System.out.println("已点击最后一道题的div子元素");

            // 点击确认按钮
            Locator confirmBtn = page.locator("#confirmAnswerBtn");
            confirmBtn.waitFor(new Locator.WaitForOptions().setTimeout(3000));
            confirmBtn.click();
            System.out.println("已点击题目确认按钮");
            page.waitForTimeout(500);

            // 提交试卷
            clickSubmitExam();

        } catch (Exception e) {
            System.err.println("处理最后一道问答题时出错：" + e.getMessage());
            saveScreenshot("last_question_error");
            throw e;
        }
    }

    /**
     * 优化弹窗关闭逻辑：1. 用精确文本/索引定位；2. 避免多元素冲突
     */
    private void closeInterferingModals() {
        try {
            System.out.println("预处理：关闭干扰弹窗...");

            // 方案3：如果有多个匹配，取第一个可见的（保底方案）
            Locator firstNoticeBtn = page.locator("//button[contains(text(), '我知道了')]").nth(0);
            if (firstNoticeBtn.isVisible(new Locator.IsVisibleOptions().setTimeout(2000))) {
                firstNoticeBtn.click();
                System.out.println("已关闭第一个'我知道了'弹窗");
                page.waitForTimeout(500);
            }

        } catch (Exception e) {
            System.out.println("无干扰弹窗或关闭失败，继续流程：" + e.getMessage());
        }
    }

    private void clickSubmitExam() {
        Locator submitBtn = page.locator("#endExamBtn");
        try {
            submitBtn.waitFor(new Locator.WaitForOptions()
                    .setState(VISIBLE)
                    .setTimeout(5000));
            submitBtn.click();
            System.out.println("已点击提交试卷按钮！");

            // 处理交卷确认
            page.waitForTimeout(2000);
            Locator confirmSubmitBtn = page.locator("#confirmEndExamBtn");
            confirmSubmitBtn.waitFor(new Locator.WaitForOptions()
                    .setState(VISIBLE)
                    .setTimeout(5000));
            confirmSubmitBtn.click();
            System.out.println("已确认交卷");

            // 等待交卷完成
            Locator submittingElement = page.locator("//*[contains(text(), '交卷中')]");
            try {
                submittingElement.waitFor(new Locator.WaitForOptions()
                        .setState(VISIBLE)
                        .setTimeout(5000));
                submittingElement.waitFor(new Locator.WaitForOptions()
                        .setState(WaitForSelectorState.HIDDEN)
                        .setTimeout(30000));
            } catch (Exception e) {
                System.out.println("未检测到交卷状态，等待结果页...");
            }

            // 结果页→再答一次→开始答题
            page.waitForURL("**/exam/result/inquire**", new Page.WaitForURLOptions().setTimeout(20000));
            System.out.println("结果页已加载");
            saveScreenshot("exam_result_page");

            Locator retryLink = page.locator("//a[contains(text(), '再答一次')]");
            retryLink.waitFor(new Locator.WaitForOptions().setTimeout(10000));
            retryLink.click();
            System.out.println("已点击再答一次");

            page.waitForURL(beforeExamUrl, new Page.WaitForURLOptions().setTimeout(10000));
            Locator startExamBtn = page.locator("#startExamBtn");
            startExamBtn.waitFor(new Locator.WaitForOptions().setTimeout(5000));
            startExamBtn.click();
            System.out.println("已点击开始答题");

            page.waitForURL(examUrl, new Page.WaitForURLOptions().setTimeout(10000));
            page.waitForLoadState(LoadState.NETWORKIDLE);
            System.out.println("答题页面加载完成");

        } catch (Exception e) {
            System.err.println("交卷流程失败：" + e.getMessage());
            saveScreenshot("submit_error");
            throw e;
        }
    }

    public void loopExam(int times) {
        for (int i = 0; i < times; i++) {
            System.out.println("\n===== 第 " + (i + 1) + " 次完整流程 =====");
            try {
                if (i == 0) {
                    page.navigate(examUrl);
                    page.waitForLoadState(LoadState.NETWORKIDLE);
                    System.out.println("首次进入答题页面");
                }
                takeExam();
                System.out.println("第 " + (i + 1) + " 次流程完成");
            } catch (Exception e) {
                System.err.println("第 " + (i + 1) + " 次流程异常：" + e.getMessage());
                saveScreenshot("loop_error_" + (i + 1));
                break;
            }
        }
    }

    public void close() {
        if (playwright != null) {
            playwright.close();
        }
    }

    public String getExamNo() {
        return examNo;
    }

    public String getExamUrl() {
        return examUrl;
    }

    public void setExamUrl(String examUrl) {
        this.examUrl = examUrl;
    }

    public String getBeforeExamUrl() {
        return beforeExamUrl;
    }

    public void setBeforeExamUrl(String beforeExamUrl) {
        this.beforeExamUrl = beforeExamUrl;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public static void main(String[] args) {
        AutoExamStar bot = new AutoExamStar();
        try {
            bot.login();
            bot.loopExam(bot.times);
        } finally {
            bot.close();
        }
    }
}